///////////////////////////////////////////////////////////////////////////////
////  (c) Chaichuk AU (chaichuk@mail.ru), 								   ////
////  2004, Chelyabinsk, NTC Privodnaya Tehnika (momentum@chel.surnet.ru)  ////
///////////////////////////////////////////////////////////////////////////////

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/dispatch.h>
#include <sys/iofunc.h>
#include <time.h>
#include <sys/netmgr.h>
#include <hw/pci.h>
#include <hw/pci_devices.h>

static	void	optproc (int, char **);

const char*	progname 	= "pci1612";
const char* driver 		= "devc-ser8250";

int first_port_num = 3;

int init_device ()
{
    void* hdl;
    int pidx;
    int phdl;
    struct pci_dev_info inf;
	uint_t base_addr, irq;
	char arg1 [10];
	char arg2 [10];
	char arg3 [10];
	char arg4 [10];
	char arg5 [10];			

    /* Connect to the PCI server */
    phdl = pci_attach (0);
    if (phdl == -1) {
        fprintf( stderr, "Unable to initialize PCI\n" );
        return EXIT_FAILURE;
    }

    /* Initialize the pci_dev_info structure */
    memset (&inf, 0, sizeof (inf));
    pidx = 0;
    inf.VendorId = 0x13fe; // Advantech
    inf.DeviceId = 0x1600;

    hdl = pci_attach_device (NULL, PCI_INIT_ALL | PCI_SHARE, pidx, &inf);
    if (hdl == NULL) {
        perror ("Unable to locate PCI-1612 device");
        pci_detach_device (hdl);
		return (-1);
    } 
    if (inf.SubsystemVendorId != 0x1612) {
    	fprintf (stderr, "Found PCI-16xx device, but it's not a PCI-1612 !!\n");
        pci_detach_device (hdl);
    	return (-1);
	}
    
    base_addr = (uint_t) PCI_IO_ADDR  (inf.PciBaseAddress[0]);
    irq = (uint_t) inf.Irq;
	pci_detach_device (hdl);
	    
   	printf ("Advantech PCI-1612 device found !!\n");		
	printf ("Base Addr = %Xh, ", base_addr);		
	printf ("IRQ = %d\n", irq);		
	
	sprintf (arg1, "-u%d", first_port_num);
	sprintf (arg2, "%x,%d", base_addr,      irq);
	sprintf (arg3, "%x,%d", base_addr + 8,  irq);
	sprintf (arg4, "%x,%d", base_addr + 16, irq);
	sprintf (arg5, "%x,%d", base_addr + 24, irq);			

	execlp (driver, driver, arg1, arg2, arg3, arg4, arg5, NULL);

	return 0;	
}

int
main (int argc, char **argv)
{

	if (ThreadCtl (_NTO_TCTL_IO, 0) == -1) {
		fprintf (stderr, "%s:  can't obtain I/O privilege; ensure you are running as root! (errno %d (%s))\n", progname, errno, strerror (errno));
		exit (EXIT_FAILURE);
	}

	optproc (argc, argv);

	init_device ();

	return (EXIT_SUCCESS);
}

static void
usageError (void)
{
	fprintf (stderr, "%s:  error in use, type \"use %s\" for usage\n", progname, progname);
	exit (1);
}

static void
optproc (int argc, char **argv)
{
	int opt;

	while ((opt = getopt (argc, argv, "u:")) != -1) {
		switch (opt) {
			case 'u': 
				first_port_num = atoi (optarg);
				break;
			
		default:
			usageError ();
			break;
		}
	}
}